// Copyright 2007 Helsinki Institute for Information Technology
// and the authors.
//
// Authors: Petri Savolainen <petri.savolainen@hiit.fi>
//          Harri Hämäläinen <harri.hamalainen@helsinki.fi>
//          Toni Ruottu <toni.ruottu@iki.fi>

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// var COLLECTION_ID = '363880bc58f194a00be83ce38a12644eebd98ef7';
var PRESENCE_FRESHNESSLIMIT = 1000 * 60;

var collection = location.pathname.split('/')[2];

function ChatConnector()
	{
	
	var self = this;	
	var messageMark = '0';
	var presenceMark = '0';	
	var messageListener = null;	
	var presenceListener = null;
    var lastMessageReceived;
		
	this.getRealName = function()
		{
		var data = HttpConnector.doGet('/info?output=json');		
		var obj = eval('('+data+')');	
		var defaultProfile = obj['default_profile'];		
		var ret = HttpConnector.doGet('/collection/'+defaultProfile+'/info/title');
		return ret;
		}
    this.getPreviousNick = function() 
        {
        var fingerprint = Util.getFingerprint();
        var data = HttpConnector.doGet('/collection/'+collection+'/chat/presence/0x'+fingerprint+'?timeout=1');
        try 
            {
            presenceData = data.evalJSON(true);
            return presenceData.nick;
            } 
        catch (e) 
            {
            return;
            }
        }
	this.onNewMessages = function(data)
		{
		messageListener.onMessagesReceived(data['data']);
		//messageMark = data['mark'];							
		//self.getNewMessages();
		}

	this.getNewMessages = function()
		{
        var url = '/collections/'+collection+'/chat/message/?output=json';
		HttpConnector.doPolling(url, 0, 3, self.onNewMessages);
        }
	
	this.listenToMessages = function(lis)
		{
		messageListener = lis;
		self.getNewMessages();
		}
	
	this.onNewPresence = function(data)
		{
		presenceListener.onPresenceReceived(data['data']);				
		//presenceMark = data['mark'];							
		//self.getNewPresence();
		}
	
	this.getNewPresence = function()
		{
        var url = '/collections/'+collection+'/chat/presence/?output=json';
        HttpConnector.doPolling(url, 0, 3, self.onNewPresence);
        }

	this.listenToPresence = function(lis)
		{
		presenceListener = lis;
		self.getNewPresence();		
		}
	
	this.pad = function(s)
		{
		var ret = ''+s;
		if (ret.length<2)
			ret='0'+ret;	
		return ret;		
		}
		
	this.postMessage = function(nick, msg)
		{
        var messageObj = {
            nick: nick,
            message: msg
        };
        messageObj['realname'] = self.getRealName();
        messageObj['profile_id'] = Util.getDefaultProfile();
        messageObj['timestamp'] = Util.getUTCDate();
        var url = '/collections/'+collection+'/chat/message/'+Util.getUTCDate();
		HttpConnector.doPost(url, Object.toJSON(messageObj));
		}	

	this.postPresence = function(nick,status)
		{
		var presenceObj = {
            nick: nick,
            status: status
        };
        var curDate = new Date();
        presenceObj['realname'] = self.getRealName();
        presenceObj['timestamp'] = curDate.getTime() - curDate.getTimezoneOffset() * 60 * 1000;
        presenceObj['profile_id'] = Util.getDefaultProfile();
		var url = '/collections/'+collection+'/chat/presence';
		HttpConnector.doPost(url, Object.toJSON(presenceObj));
		}	
	}

function PresenceItem(nickname, realname, profile_id, updateTime, status)
	{
	var self = this;
	this.getNickname = function()
		{
		return nickname;		
		}
    this.getRealname = function()
        {
        return realname;
        }
    this.getProfileId = function()
        {
        return profile_id;
        }
	this.getUpdateTime = function()
		{
		return updateTime;		
		}
	this.getStatus = function()
		{
		return status;		
		}
	
    this.equals = function(other)
		{
		if (other.getProfileId()==profile_id)
			return true;
		return false;		
		}	
	}

function ChatMessage(timestamp, profile_id, nickname, realname, message)
	{
	var date = Util.parseUTCDate(timestamp);	

    var localDate = Util.getUTCFriendlyDate(timestamp);

    this.getDate = function()
		{
		return date;		
		}	

	this.getTime = function()
		{
		return date.getTime();		
		}
	
    this.toHtml = function()	
		{
		var inner = '';
		var clockTime = localDate.match(/(\d+:\d+):\d+/)[1];
        	inner += '<tr><td class="timecell">'+clockTime+'</td><td class=\"nickcell\" title=\"';
		inner += realname + '\"> <a href=\"/profile/'+profile_id+'\">';
		inner += nickname + '</a></td> <td class=\"messagecell\">'
		inner += message + '</td></tr>\n'; 
		return inner;		
		}
	}

function ChatWindow(divid, nickinputid, messageinputid, presenceulid)
	{
    
	var self = this;

	//var chatDiv = document.getElementById(divid);
	var chatTable = document.getElementById(divid);
	chatTable.innerHTML = '';	

	var chatConnector = new ChatConnector(); 	
	var presenceUl = document.getElementById(presenceulid);

	var nickInput = document.getElementById(nickinputid);
	nickInput.value = chatConnector.getPreviousNick() || chatConnector.getRealName().split(' ')[0]; 
	
	var messageInput = document.getElementById(messageinputid);

	var presenceVector = new Vector();
	var messageVector = new Vector();	

    var currentStyle = 'litestyle';

    this.getDayChangedHtml = function(date1, date2) 
	    {
        var v = date1.split('-');
        var year = parseInt(v[0],10);
	    var month = parseInt(v[1], 10);
        var day = parseInt(v[2], 10);
        date1 = year+'-'+month+'-'+day;
        
        v = date2.split('-');
        var year = parseInt(v[0],10);
        var month = parseInt(v[1], 10);
        var day = parseInt(v[2], 10);
        date2 = year+'-'+month+'-'+day;
        
        var safety = 1000;
        var html = '';
        while( date1 != date2 && safety > 0)
            {
            safety -= 1;
            looppasi = true;
            date1 = chatWindow.nextDay(date1);
            
            html += '<tr class="systemmessage"><td class="timecell">00:00</td>'
                    +'<td class="nickcell"></td><td class="messagecell">'
                    +'Day changed to '+date1+'</td></tr>';
            }
        return html;
        }

    this.nextDay = function(day)
        {
        var v = day.split('-');
        var year = parseInt(v[0],10);
        var month = parseInt(v[1], 10);
        var day = parseInt(v[2], 10);
	    var days = [null,31,28,31,30,31,30,31,31,30,31,30,31];
        if(year % 400 == 0)
            days[2] = 29
        else if (year % 100 == 0)
            days[2] = 28
        else if (year % 4 == 0)
            days[2] = 29
        else
            days[2] = 28

        day += 1;

        if(day > days[month])
            {
                month += 1;
                day = 1;

            if(month > 12)
                    {
                        month = 1;
                        year += 1;
                    }
            }


        return year+'-'+month+'-'+day;
        }

	
	this.addMessage = function(datetime, profile_id, nick, realname, msg)
		{
		//msg = msg.substring(0,20); 
		/*		
		var row = document.createElement('tr');
	
		var nickCell = document.createElement('td');		
		nickCell.className = 'nickcell';		
		nickCell.title = nick; 		
		var anc = document.createElement('a');
		anc.href = 'http://localhost:8080/profile/9786e899eec683bfecb8b2bc9067a7efae95169c';	
		anc.appendChild(document.createTextNode(nick));		
		nickCell.appendChild(anc);
		row.appendChild(nickCell);		
				
		var messageCell = document.createElement('td');
		messageCell.className = 'messagecell';		
		messageCell.appendChild(document.createTextNode(msg));
		row.appendChild(messageCell);
		
		chatTable.appendChild(row);		
		*/

		// add the message into its right place in the vector
		// according to time		
		
		var tempMessage = new ChatMessage(datetime, profile_id, nick, realname, msg);
		
		var i = 0;
		if ( messageVector.size() == 0 || (tempMessage.getTime()> messageVector.get(messageVector.size()-1).getTime()) )
			{			
			i= messageVector.size();
			}
		else	
            {
			for (i=0; i<messageVector.size(); i++)
				{
				if (tempMessage.getTime() < messageVector.get(i).getTime())
					break;								
				}
			}	
		messageVector.insert(i, tempMessage);	

		//alert(messageVector.size());
		
		var sdate = datetime.match(/(\d+-\d+-\d+)/)[1];

			
		if (i == (messageVector.size()-1))	//the message was added to the end	
			{                               //add one message
        	var inner = '';
			if ( messageVector.size()>1 )
				{
				var date1 = tempMessage.getDate();
				var date2 = messageVector.get(messageVector.size()-2).getDate();	
				if (!Util.isSameDate(date1,date2))
					inner += self.getDayChangedHtml(Util.formatDate(date2),Util.formatDate(date1));				
				} 
			else	
                {
				inner += self.getDayChangedHtml(sdate,sdate);
				}   
				
        	inner += tempMessage.toHtml(); 
			chatTable.innerHTML += inner;
				
			}
		
		else 	{	//message was added to somewhewre else, redraw all messages		
			var content = '';			
			for (var j=0; j<messageVector.size(); j++)				
				{
				
				if ((j-1) >= 0)
					{
					var date1 = messageVector.get(j).getDate();
					var date2 = messageVector.get(j-1).getDate();	
					if (!Util.isSameDate(date1,date2))
						content += self.getDayChangedHtml(Util.formatDate(date1));						
					}
				else	{
					inner += self.getDayChangedHtml(sdate);
					}
							
				content += messageVector.get(j).toHtml(); 				
				}			

			chatTable.innerHTML = content;
			}

		chatTable.scrollTop = chatTable.scrollHeight;	
		}

	this.onMessagesReceived = function(data)
		{
		for (var i=0; i<data.length; i++)
			{
            try 
                {
                var messageObj = data[i][1].evalJSON(true);
			    self.addMessage(Util.escape(messageObj.timestamp),
                                Util.escape(messageObj.profile_id),
                                Util.escape(messageObj.nick),
                                Util.escape(messageObj.realname),
                                Util.escape(messageObj.message));
			    }
            catch(e)
                {
                //alert("E:"+e);
                }
            }
		}

    this.setActiveStyleSheet = function(sid)
        {
        var links = document.getElementsByTagName("link");
        for(var i=0; i<links.length ; i++)
            {
            if(links[i].getAttribute("rel").indexOf("style") != -1 && links[i].getAttribute("id"))
                {
                links[i].disabled = true;
                if (links[i].getAttribute("id") == sid)
                    links[i].disabled = false;
                }
            }
        }
       
    this.toggleStyle = function()
        {
        if (currentStyle == 'litestyle')
            currentStyle = 'heavystyle';
        else
            currentStyle = 'litestyle';
        self.setActiveStyleSheet(currentStyle);
        }

	this.addPresenceLi = function(nick, profile_id, realname)
		{
		var li = document.createElement('li');
		li.title = realname;		
		var anc = document.createElement('a');
		anc.href = '/profile/'+profile_id;	
		anc.appendChild(document.createTextNode(nick));	
		li.appendChild(anc);
		presenceUl.appendChild(li);		
		}

	this.renderPresence = function()
		{
		var currentDate = new Date();
		
		presenceUl.innerHTML = '';
		
		for (var i=0; i<presenceVector.size(); i++)	
			{	
			var temp = presenceVector.get(i);
            if (((currentDate.getTime() - currentDate.getTimezoneOffset() * 60 * 1000) - temp.getUpdateTime()) < PRESENCE_FRESHNESSLIMIT )
				{
				if (temp.getStatus()=='present')				
					{
					self.addPresenceLi( Util.escape(temp.getNickname()), 
                                        Util.escape(temp.getProfileId()), 
                                        Util.escape(temp.getRealname()));
					}
                else if (temp.getStatus()=='away')
                    {
                    self.addPresenceLi( Util.escape(temp.getNickname())+' (away)', 
                                        Util.escape(temp.getProfileId()), 
                                        Util.escape(temp.getRealname()));
                    }
				}			
			}	
		}	

	this.updatePresence = function(item)
		{
		
		for (var i=0; i<presenceVector.size(); i++)
			{
			if (item.equals(presenceVector.get(i)))
				{			
				presenceVector.set(i,item);
				return;
				}			
			}
		presenceVector.add(item);
		}

	this.onPresenceReceived = function(data)
		{
		try	{
			for (var i=0; i<data.length; i++)
				{
				try 
                    {
                    var presenceObj = data[i][1].evalJSON(true);

				    var dat = new Date();			
				    dat.setTime(parseInt(presenceObj['timestamp']));
				    self.updatePresence(new PresenceItem(
                                    presenceObj['nick'],
                                    presenceObj['realname'],
                                    presenceObj['profile_id'],
                                    dat, 
                                    presenceObj['status']));
				    } 
                catch(e) 
                    {
                    continue;
                    }
				}
			self.renderPresence();	
			}		
			catch (e1) 
				{
				//alert("E:"+e1);
                }	
		}	
	
	this.displayNickError = function()
		{
		//var nickLabel = document.getElementById('nickinputlabel');
		//nickLabel.className = 'errortext';
		var nickInput = document.getElementById('nickinput');		
		nickInput.className = 'errorborder';
		}
	
	this.hideNickError = function()
		{
		//var nickLabel = document.getElementById('nickinputlabel');
		//nickLabel.className = '';
		var nickInput = document.getElementById('nickinput');		
		nickInput.className = '';
		}


	this.onMessageEntered = function()
		{
		var nick = nickInput.value;		
		var msg = messageInput.value; 		
		//self.hideNickError();
		if (nick=='')
			{
			self.displayNickError();			
			return;			
			}		
		
		if (msg =='')
			return;

		messageInput.value = '';		
		//alert('trying to post message');		
		chatConnector.postMessage(nick,msg);	 
		}

	this.postOwnPresence = function()
		{
		//alert('posting ownpresence');
		new PeriodicalExecuter(function() 
            {
            var nick = nickInput.value;
	    	if (nick!='')
		    	chatConnector.postPresence(nick,'present')		
		    }, 5);
		}
	
	messageInput.onkeydown = function(e) 
					{
				 	if (e.keyCode == 13) 
						{
						self.onMessageEntered();
						return false;						
						}	
					};
	nickInput.onChange = function()
		{
		self.postOwnPresence();
		}
	
	chatConnector.listenToMessages(self);
	chatConnector.listenToPresence(self);
	this.postOwnPresence();

    	document.getElementById('effecttoggle').onclick = self.toggleStyle;
    }


var chatWindow = null;
   
window.onload = function()
	{
	chatWindow = new ChatWindow('messagewindow','nickinput','messageinput','presencewindow');		
	}
